package com.lcm.openapi.scanner;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.lcm.openapi.config.GenerateConfig;
import com.lcm.openapi.core.GenerateUtil;
import com.lcm.openapi.core.model.ApiModel;
import com.lcm.openapi.core.model.ApiModelField;
import com.lcm.openapi.generator.NameGenerator;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.Set;

@Slf4j
public class ApiModelScanner {

    private GenerateConfig generateConfig;

    public ApiModelScanner(GenerateConfig generateConfig) {
        this.generateConfig = generateConfig;
    }

    /**
     * 扫描json，解析出model对象
     *
     * @param dataJson 数据源json
     * @return mode对象
     */
    public List<ApiModel> scan(JSONObject dataJson) {
        //根据openapi3.0规范,所有的model描述都存放在components -> schemas
        JSONObject components = dataJson.getJSONObject("components");
        if (CollectionUtil.isEmpty(components)) {
            return new ArrayList<>();
        }
        JSONObject schemas = components.getJSONObject("schemas");
        if (CollectionUtil.isEmpty(schemas)) {
            return new ArrayList<>();
        }
        //名称生成器
        NameGenerator nameGenerator = generateConfig.getNameGenerator();
        List<ApiModel> result = new ArrayList<>();
        //遍历schema
        schemas.forEach((k, v) -> {
            log.info("开始解析模型:{}", k);
            //初始化apiModel
            ApiModel apiModel = new ApiModel();
            apiModel.setModelName(k);
            apiModel.setPackageName(generateConfig.getModelPackage());
            //解析模型
            this.analyseModel(apiModel, (JSONObject) v, nameGenerator);
            result.add(apiModel);
        });
        return result;
    }

    private void analyseModel(ApiModel apiModel, JSONObject modelJson, NameGenerator nameGenerator) {
        //是否必须
        List<String> required = new ArrayList<>();
        if (modelJson.containsKey("required")) {
            required.addAll(modelJson.getJSONArray("required").toJavaList(String.class));
        }
        //模型名称
        String modelDesc = modelJson.getString("title");
        if (StrUtil.isEmpty(modelDesc)) {
            modelDesc = modelJson.getString("description");
        }
        if (StrUtil.isEmpty(modelDesc)) {
            modelDesc = apiModel.getModelName();
        }
        apiModel.setModelDesc(modelDesc);

        //模型字段描述
        JSONObject properties = modelJson.getJSONObject("properties");
        List<ApiModelField> apiModelFields = new ArrayList<>();
        Optional.ofNullable(properties).ifPresent(prop -> {
            prop.forEach((m, n) -> {
                //解析模型字段
                ApiModelField apiModelField = this.analyseModelField(m, required, (JSONObject) n, apiModel);
                this.setFieldValidate(apiModelField);
                apiModelFields.add(apiModelField);
            });
            apiModel.setApiModelFields(apiModelFields);
            apiModel.setModelName(nameGenerator.generateModelName(apiModel));
        });
        Set<String> imports = apiModel.getImports();
        imports.remove(null);
    }

    //解析model对象
    private ApiModelField analyseModelField(String fieldName, List<String> required, JSONObject propJson, ApiModel apiModel) {
        ApiModelField apiModelField = new ApiModelField();
        //字段名
        apiModelField.setFieldName(fieldName);
        //是否必须
        apiModelField.setRequired(required.contains(fieldName));
        //字段描述
        String title = propJson.getString("title");
        if(StrUtil.isEmpty(title)){
            title = propJson.getString("description");
        }
        apiModelField.setFieldDesc(title);
        //数据类型共三种,普通数据类型,array,$ref模型引用
        //字段类型
        String type = propJson.getString("type");
        if (StrUtil.isNotEmpty(type)) {
            //引入相关包
            apiModel.getImports().add(GenerateUtil.findDependency(type));
            //字段类型不为空,可能是普通数据类型,array
            //转换java数据类型
            String javaType = GenerateUtil.toJavaType(type);
            apiModelField.setFieldType(javaType);
            if (GenerateUtil.JAVA_TYPE_LIST.equals(javaType)) {
                //如果javaType是list,则需要解析泛型
                apiModelField.setRecursiveCheck(true);
                apiModelField.setFieldType(GenerateUtil.transJavaListGeneric(apiModelField.getFieldType(), propJson, apiModel.getRefModels()));
            }
        } else {
            //字段类型为空必定是$ref模型引用
            String ref = GenerateUtil.analyseRef(propJson);
            if (StrUtil.isNotEmpty(ref)) {
                //引用类型
                apiModelField.setFieldType(ref);
                //关联
                apiModel.getRefModels().add(ref);
                apiModelField.setRecursiveCheck(true);
            }
        }
        return apiModelField;
    }

    //设置字段验证
    private void setFieldValidate(ApiModelField apiModelField) {
        String fieldType = apiModelField.getFieldType();
        if (StrUtil.isNotEmpty(fieldType) && apiModelField.isRequired()) {
            switch (fieldType) {
                case "String":
                    apiModelField.setStringCheck(true);
                    break;
                case "Integer":
                case "Object":
                case "BigDecimal":
                    apiModelField.setNullCheck(true);
                    break;
                default:
                    //递归验证
                    apiModelField.setRecursiveCheck(true);
                    if (fieldType.startsWith("List")) {
                        apiModelField.setListCheck(true);
                    }
                    break;
            }
        }
    }

}
